/**
 * @SharingPool.as
 *
 * @author sodaChen mail:asframe@qq.com
 * @version 1.0
 * <br>Copyright (C), 2013 ASFrame.com
 * <br>This program is protected by copyright laws.
 * <br>Program Name:ASFrame
 * <br>Date:2013-8-22
 */
package com.asframe.mgr
{
	import com.asframe.ASF;
	import com.asframe.pattern.Singleton;
	import com.asframe.pool.IObjectPool;
	import com.asframe.utils.DestroyUtils;

	import flash.utils.Dictionary;
	import flash.utils.clearTimeout;
	import flash.utils.setTimeout;

	/**
	 * 共享对象池，提供引用次数的计算
	 * @author sodaChen
	 * #Date:2013-8-22
	 */
	public class RefMgr extends Singleton
	{
		private static var instance	:RefMgr;

		/** 通过key引用target记录 **/
		private var refMap			:Dictionary;
		/** 通过target本身作为引用，来保存target记录 **/
		private var targetMap		:Dictionary;
		/** 对象 **/
		private var poolObject		:IObjectPool;

		/**
		 * 获取实例的静态方法实例
		 * @return
		 *
		 */
		public static function getInstance():RefMgr
		{
			if(instance == null)
			{
				instance = new RefMgr();
			}
			return instance;
		}

		public function RefMgr()
		{
			refMap = new Dictionary();
			targetMap = new Dictionary();
			PoolMgr.getInstance().registerClass(ReferData);
			poolObject = PoolMgr.getInstance().getObjectPool(ReferData);
		}

		/**
		 * 添加一个引用共享对象
		 * @param key 唯一key
		 * @param target 共享对象
		 * @param isRefer 是否马上增加一次引用
		 *
		 */
		public function addRefer(key:String,target:*,isRefer:Boolean = true):void
		{
			var referData:ReferData = refMap[key];
			if (referData != null)
			{
				throw new Error(key + "重复添加Refer");
			}
			if (target == null)
			{
				throw new Error("target为空！");
			}
			referData = poolObject.borrowObject();
			refMap[key] = referData;
			targetMap[target] = referData;
			referData.key = key;
			referData.target = target;
			if(isRefer)
			{
				referData.refCount++;
			}
		}
		/**
		 * 指定的key是否存在共享对象的引用
		 * @param key 唯一
		 * @return true则表示存在，否则不存在
		 *
		 */
		public function hasRefer(key:String):Boolean
		{
			if(key == null)
				return false;
			return refMap[key] != null;
		}
		/**
		 * 指定key取得一个公共引用对象（对象的引用次数会增加1） 如果没有对象则会抛出异常
		 * @param key 唯一字符串
		 * @return 公共对象
		 */
		public function refer(keyOrTarget:*):*
		{
			var referData:ReferData = refMap[keyOrTarget];
			if (referData == null)
			{
				referData = targetMap[keyOrTarget];
				if (referData == null)
					throw new Error(keyOrTarget + "没有对应的Refer，请先添加");
			}
			referData.refCount++;
			if(referData.timeId != 0)
			{
				//表示被重新引用了，清除原来的销毁计时器
				clearTimeout(referData.timeId);
				referData.timeId = 0;
			}
			return referData.target;
		}
		/**
		 * 清除所有的共享缓存资源
		 * @param isDestory 清除的同时销毁缓存的资源，默认是销毁
		 *
		 */
		public function clearAll(isDestory:Boolean = true):void
		{
			if(isDestory)
			{
				for each (var referData:ReferData in refMap)
				{
					DestroyUtils.destroyObj(referData.target);
					delete targetMap[referData.target];
					referData.destroy();
				}
				for each (var referData1:ReferData in targetMap)
				{
					DestroyUtils.destroyObj(referData1.target);
					referData.destroy();
				}
			}
			refMap = new Dictionary();
			targetMap = new Dictionary();
		}
		/**
		 * 取消一次公共对象的引用
		 * @param keyOrTarget 唯一key或者共享对象实例
		 * @param isDestroy 立刻销毁对象，否则是引用次数为0时30(可配置设定)秒后销毁
		 *
		 */
		public function unrefer(keyOrTarget:*,isDestroy:Boolean = false):void
		{
			//优先从key取值
			var referData:ReferData = refMap[keyOrTarget];
			if (referData == null)
			{
				referData = targetMap[keyOrTarget];
				if (referData == null) return ;
			}
			referData.refCount--;
			if (referData.refCount <= 0)
			{
				if(isDestroy)
					//强制销毁，没有延迟
					recover(referData);
				else
					//ASF.sharingPoolDelay后清除资源
					referData.timeId = setTimeout(recover,ASF.sharingPoolDelay,referData);
			}
		}
		private function recover(referData:ReferData):void
		{
			clearTimeout(referData.timeId);
			//防止延迟销毁期间又被引用
			if (referData.refCount > 0) return;

			//资源进行销毁
			delete refMap[referData.key];
			delete targetMap[referData.target];
			//判断是否销毁实例
			var target:* = referData.target;
			DestroyUtils.destroyObj(target);
			referData.destroy();
			//放回对象池
			poolObject.returnObject(referData);
		}
	}
}
import com.asframe.mgr.PoolMgr;

class ReferData
{
	public var timeId:Number = 0;
	public var key:String;
	public var target:*;
	public var refCount:int;

	public function ReferData()
	{
	}

	public function destroy():void
	{
		key = null;
		target = null;
		refCount = 0;
		timeId = 0;
//		PoolMgr.getInstance().returnObject(this,ReferData);
	}
}
